package cn.juque.lucenecandy.core.datasync.tcc;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ClassUtil;
import cn.juque.common.constants.YesOrNoEnum;
import cn.juque.lucenecandy.bo.IndexBO;
import cn.juque.lucenecandy.core.base.BaseEntity;
import cn.juque.lucenecandy.core.constants.StrConstant;
import cn.juque.lucenecandy.helper.DocumentHelper;
import cn.juque.lucenecandy.helper.IndexHelper;
import cn.juque.lucenecandy.helper.LuceneHelper;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.IntPoint;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.TermQuery;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author juque
 * @version 1.0.0
 * <ul>
 *     <li>CandyCancelService</li>
 * </ul>
 * @date 2023-12-28
 **/
@Service("candyCancelService")
public class CandyCancelServiceImpl implements ITccService {

    @Resource
    private LuceneHelper luceneHelper;

    @Resource
    private DocumentHelper documentHelper;

    @Resource
    private IndexHelper indexHelper;

    /**
     * 添加文档
     *
     * @param entityList 列表
     */
    @Override
    public void add(List<? extends BaseEntity> entityList) {
        if (CollUtil.isEmpty(entityList)) {
            return;
        }
        // 根据id删除
        BooleanQuery.Builder builder = new BooleanQuery.Builder();
        entityList.forEach(f-> builder.add(new TermQuery(new Term(StrConstant.D_ID, f.getId())), BooleanClause.Occur.SHOULD));
        IndexBO indexBO = this.documentHelper.index(entityList.get(0).getClass());
        this.luceneHelper.deleteDocuments(indexBO.getIndexName(), builder.build());
    }

    /**
     * 更新文档
     *
     * @param entityList 列表
     */
    @Override
    public void update(List<? extends BaseEntity> entityList) {
        if (CollUtil.isEmpty(entityList)) {
            return;
        }
        entityList.forEach(f->{
            Class<? extends BaseEntity> tClass = ClassUtil.getClass(f);
            IndexBO indexBO = this.documentHelper.index(tClass);
            // 删除当前版本
            BooleanQuery.Builder builder = new BooleanQuery.Builder();
            builder.add(new TermQuery(new Term(StrConstant.D_ID, f.getId())), BooleanClause.Occur.MUST);
            builder.add(IntPoint.newExactQuery(StrConstant.D_VERSION, f.getVersion()), BooleanClause.Occur.MUST);
            this.luceneHelper.deleteDocuments(indexBO.getIndexName(), builder.build());
            // 上一个版本可见
            builder = new BooleanQuery.Builder();
            builder.add(new TermQuery(new Term(StrConstant.D_ID, f.getId())), BooleanClause.Occur.MUST);
            int version = f.getVersion() - 1;
            builder.add(IntPoint.newExactQuery(StrConstant.D_VERSION, version), BooleanClause.Occur.MUST);
            List<Document> source = this.luceneHelper.search(indexBO.getIndexName(), builder, Sort.INDEXORDER, null);
            this.indexHelper.switchDoc(this.documentHelper.toEntityList(source, tClass), YesOrNoEnum.YES);
        });
    }

    /**
     * 删除文档
     *
     * @param className 实体类名
     * @param idList    主键列表
     */
    @Override
    public void del(String className, List<String> idList) {
        if (CollUtil.isEmpty(idList)) {
            return;
        }
        // 根据id检索出所有版本
        Class<? extends BaseEntity> tClass = ClassUtil.loadClass(className);
        IndexBO indexBO = this.documentHelper.index(tClass);
        BooleanQuery.Builder builder = new BooleanQuery.Builder();
        idList.forEach(f -> builder.add(new TermQuery(new Term(StrConstant.D_ID, f)), BooleanClause.Occur.SHOULD));
        List<Document> docList = this.luceneHelper.search(indexBO.getIndexName(), builder, Sort.INDEXORDER, null);
        if (CollUtil.isEmpty(docList)) {
            return;
        }
        Map<String, List<Document>> docMap = docList.stream().collect(Collectors.groupingBy(d -> d.get(StrConstant.D_ID)));
        // 过滤出最新版本，并更新为可见
        docMap.forEach((id, list) -> {
            // 根据版本号倒序
            list = list.stream().sorted(
                    Comparator.comparing(c -> Integer.parseInt(c.get(StrConstant.D_VERSION)),
                            Comparator.reverseOrder())).collect(Collectors.toList());
            // 最新版本变更为可见
            Document d = list.get(0);
            List<Document> dList = new ArrayList<>(1);
            dList.add(d);
            this.indexHelper.switchDoc(this.documentHelper.toEntityList(dList, tClass), YesOrNoEnum.YES);
            // 其他低版本统一删除
            int minVersion = Integer.parseInt(d.get(StrConstant.D_VERSION)) - 1;
            BooleanQuery.Builder delBuilder = new BooleanQuery.Builder();
            delBuilder.add(new TermQuery(new Term(StrConstant.D_ID, id)), BooleanClause.Occur.MUST);
            delBuilder.add(IntPoint.newRangeQuery(StrConstant.D_VERSION, Integer.MIN_VALUE, minVersion), BooleanClause.Occur.MUST);
            this.luceneHelper.deleteDocuments(indexBO.getIndexName(), delBuilder.build());
        });
    }
}
